#include "uproxystyle.h"
#include "upalette.h"
#include "ustyleoption.h"
#include "uprogressstyleoption.h"
#include "uwidgetutils.h"

#include <qdrawutil.h>
#include <QPixmap>
#include <QPainter>
#include <QStyleOptionMenuItem>
#include <QPainterPath>
#include <QApplication>

namespace
{
    const int FRAME_BORDER_RADIUS = 2;
    const int ICON_PIXEL_SIZE = 16;
    const int ICON_LEFT_MARGIN = 8;
    const int MARGINS = 0;
    const int LEFT_MARGIN = ICON_PIXEL_SIZE + ICON_LEFT_MARGIN * 2;
}  // namespace

RadiuPosition radiuPosition(const QStyleOptionViewItem::ViewItemPosition &viewItemPosition)
{
    RadiuPosition position = RadiuPosition::All;
    switch (viewItemPosition)
    {
        case QStyleOptionViewItem::ViewItemPosition::Beginning:
        {
            position = RadiuPosition::Top;
            break;
        }
        case QStyleOptionViewItem::ViewItemPosition::Middle:
        {
            position = RadiuPosition::Normal;
            break;
        }
        case QStyleOptionViewItem::ViewItemPosition::End:
        {
            position = RadiuPosition::Bottom;
            break;
        }
        case QStyleOptionViewItem::ViewItemPosition::OnlyOne:
        {
            position = RadiuPosition::All;
            break;
        }
        default:
            break;
    }
    return position;
}

UProxyStyle::UProxyStyle()
    : QProxyStyle()
{
}

UProxyStyle::~UProxyStyle()
{
}

UTheme::ThemeType UProxyStyle::theme() const
{
    return m_theme.theme();
}

void UProxyStyle::setTheme(const UTheme::ThemeType &type)
{
    m_theme.setTheme(type);
    QString themeName(m_theme.themeName());
    QIcon::setThemeName(themeName);
    QIcon::setFallbackThemeName(themeName);
    emit themeChanged(type);
}

QPalette UProxyStyle::standardPalette() const
{
    return *m_theme.palette();
}

UPalette* UProxyStyle::palette() const
{
    return m_theme.palette();
}

int UProxyStyle::styleHint(QStyle::StyleHint hint,
                           const QStyleOption* option,
                           const QWidget* widget,
                           QStyleHintReturn* returnData) const
{
    return QProxyStyle::styleHint(hint, option, widget, returnData);
}

int UProxyStyle::pixelMetric(QStyle::PixelMetric metric,
                             const QStyleOption* option,
                             const QWidget* widget) const
{
    switch (metric)
    {
        case QStyle::PM_MenuScrollerHeight:
            return 15;
        case QStyle::PM_SubMenuOverlap:
            return 0;
        case QStyle::PM_MenuHMargin:
            return 2;
        case QStyle::PM_MenuVMargin:
            return 4;
        case QStyle::PM_MenuPanelWidth:
            return 1;
        case QStyle::PM_MenuTearoffHeight:
            return 0;
        case QStyle::PM_MenuDesktopFrameWidth:
            return 0;
        case QStyle::PM_SliderLength:
            return 30;
        case PM_ScrollBarExtent:
            return 8;
        default:
            return QProxyStyle::pixelMetric(metric, option, widget);
    }
}

int UProxyStyle::pixelMetric(UPixelMetric metric, const QStyleOption* option, const QWidget* widget) const
{
    switch (metric)
    {
        case UProxyStyle::PM_FocusBorderWidth:
            return 1;
        case UProxyStyle::PM_FocusBorderSpacing:
            return 6;
        case UProxyStyle::PM_FrameRadius:
            return 8;
        case UProxyStyle::PM_ShadowRadius:
            return 10;
        case UProxyStyle::PM_FrameMargins:
            return 9;
        default:
            break;
    }

    return -1;
}

void UProxyStyle::drawControl(QStyle::ControlElement element, const QStyleOption* option,
                              QPainter* painter, const QWidget* widget) const
{
    switch (element)
    {
        case CE_MenuTearoff:
            break;
        case CE_MenuEmptyArea: //空白区域
            break;
        case CE_MenuItem: //画菜单项
            if (const QStyleOptionMenuItem* menuItem = qstyleoption_cast<const QStyleOptionMenuItem*>(option))
            {
                painter->save();
                bool hover = (menuItem->state & State_Selected) && (menuItem->state & State_Enabled);
                if (hover)   //鼠标滑过，先画一个矩形，使后面的文字不会被覆盖
                {
                    painter->setBrush(menuItem->palette.brush(colorGroup(menuItem->state), QPalette::Highlight));
                    painter->drawRect(menuItem->menuRect.adjusted(MARGINS, 0, -MARGINS, 0));
                }

                if (menuItem->menuItemType == QStyleOptionMenuItem::Separator)  //画分隔线
                {
                    drawSeparator(menuItem, painter);
                }
                else if (menuItem->menuItemType == QStyleOptionMenuItem::SubMenu)   //画子菜单
                {
                    drawSubMenuItem(menuItem, painter);
                }
                else     //文字菜单项
                {
                    if (menuItem->checked)
                    {
                        if (!(menuItem->state & State_Enabled)) {
                            painter->setOpacity(0.3);
                        }
                        QRect textRect = menuItem->rect;
                        textRect.moveLeft(ICON_LEFT_MARGIN);
                        textRect = visualRect(menuItem->direction, menuItem->rect, textRect);
                        painter->setRenderHint(QPainter::Antialiasing);
                        painter->setPen(QPen(palette()->color(QPalette::Text), 2));
                        painter->drawLine(textRect.x(), textRect.y() + textRect.height() / 2, textRect.x() + 5, textRect.y() + textRect.height() / 2 + 5);
                        painter->drawLine(textRect.x() + 5, textRect.y() + textRect.height() / 2 + 5, textRect.x() + 13, textRect.y() + textRect.height() / 2 - 4);
                        painter->setOpacity(1.0);
                    }
                    drawMenuItem(menuItem, painter);
                }

                painter->restore();
            }
            break;
        case CE_ProgressBar:
            if (const UProgressStyleOption * upso
                = qstyleoption_cast<const UProgressStyleOption*>(option))
            {
                painter->save();
                if (!(upso->state & State_Enabled)) {
                    painter->setOpacity(0.3);
                }
                painter->setRenderHints(QPainter::RenderHint::Antialiasing);
                QPen pen(Qt::yellow, upso->borderWidth);
                auto borderColor = palette()->color(upso->borderRole);
                painter->setPen(upso->borderWidth == 0 ? Qt::NoPen
                                : QPen(borderColor, upso->borderWidth));
                painter->setBrush(palette()->brush(upso->bgRole));
                auto halfPenWidth = upso->borderWidth / 2;
                painter->drawRoundedRect(upso->rect.adjusted(halfPenWidth, halfPenWidth, -halfPenWidth, -halfPenWidth),
                                         upso->radius, upso->radius);

                auto textRect = upso->fontMetrics.boundingRect(upso->text);

                // 画进度
                painter->setBrush(palette()->brush(upso->progressRole));
                auto progressRect = upso->rect;
                auto ratio = qreal(upso->progress) / qreal(upso->maximum - upso->minimum);
                if (upso->orientation == Qt::Vertical) // 进度条的方向
                {
                    progressRect = QRect(upso->rect.y(), upso->rect.x(), upso->rect.height(), upso->rect.width());
                }

                if (upso->invertedAppearance) // 进度反向
                {
                    progressRect.setX(progressRect.width() - progressRect.width()*ratio);
                    textRect.moveTo(progressRect.x() + 5, 0);
                    textRect.setHeight(progressRect.height());
                }
                else
                {
                    progressRect.setWidth(progressRect.width()*ratio);
                    textRect.moveTo(progressRect.width() - textRect.width() - 5, 0);
                    textRect.setHeight(progressRect.height());
                }

                if (upso->orientation == Qt::Vertical)
                {
                    int y = 0;
                    if (upso->invertedAppearance)
                    {
                        progressRect = QRect(0, 0,
                                             progressRect.height(), upso->rect.height() - progressRect.x());
                        y = progressRect.height() - textRect.width() - 5;
                    }
                    else
                    {
                        progressRect = QRect(progressRect.x(), upso->rect.height() - progressRect.width(),
                                             progressRect.height(), progressRect.width());
                        y = progressRect.y() + 5;
                    }
                    auto x = -(textRect.width() - progressRect.width()) / 2;
                    textRect.moveTo(x, y);
                }
                // 当进度值为最小值时，不绘制进度值
                if (upso->progress > upso->minimum)
                {
                    painter->drawRoundedRect(progressRect.adjusted(halfPenWidth, halfPenWidth, -halfPenWidth, -halfPenWidth),
                                             upso->radius, upso->radius);
                }
                painter->restore();

                // 画文本
                if (upso->textVisible)
                {
                    if (upso->orientation == Qt::Vertical)
                    {
                        painter->translate(textRect.center());
                        painter->rotate(-90);
                        painter->translate(-textRect.center());
                    }
                    drawItemText(painter, textRect, upso->textAlignment,
                                 upso->palette, upso->state & State_Enabled, upso->text, QPalette::WindowText);
                }
            }
            break;
        default:
            QProxyStyle::drawControl(element, option, painter, widget);
            break;
    }
}

void UProxyStyle::drawControl(UControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
{
    switch (element)
    {
        case CE_RadioButton:
        case CE_CheckBox:
            if (const QStyleOptionButton* btn = qstyleoption_cast<const QStyleOptionButton*>(option))
            {
                bool isRadio = (element == CE_RadioButton);
                QStyleOptionButton subopt = *btn;
                subopt.rect = subElementRect(isRadio ? SE_RadioButtonIndicator
                                             : SE_CheckBoxIndicator, btn, widget);
                subopt.rect = subopt.rect.adjusted(1, 0, 0, 0);
                drawPrimitive(isRadio ? PE_IndicatorRadioButton : PE_IndicatorCheckBox,
                              &subopt, painter, widget);
                subopt.rect = subElementRect(isRadio ? SE_RadioButtonContents
                                             : SE_CheckBoxContents, btn, widget);
                subopt.rect = subopt.rect.adjusted(1, 0, 0, 0);
                uint alignment = visualAlignment(subopt.direction, Qt::AlignLeft | Qt::AlignVCenter);
                QPixmap pix;
                QRect textRect = subopt.rect;
                if (!subopt.icon.isNull())
                {
                    QWindow* window = widget ? widget->window()->windowHandle() : nullptr;
                    pix = subopt.icon.pixmap(window, subopt.iconSize, subopt.state & State_Enabled ? QIcon::Normal : QIcon::Disabled);
                    drawItemPixmap(painter, subopt.rect, alignment, pix);
                    if (subopt.direction == Qt::RightToLeft)
                        textRect.setRight(textRect.right() - subopt.iconSize.width() - 4);
                    else
                        textRect.setLeft(textRect.left() + subopt.iconSize.width() + 4);
                }
                if (!subopt.text.isEmpty())
                {
                    drawItemText(painter, textRect, alignment | Qt::TextShowMnemonic,
                                 subopt.palette, subopt.state & State_Enabled, subopt.text, QPalette::WindowText);
                }
            }
            break;
        case CE_UCommonButton:
            if (const UCommonButtonOption* btn = qstyleoption_cast<const UCommonButtonOption*>(option))
            {
                painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
                QPainterPath framePath = UWidgetUtils::roundedPath(btn->radius, btn->rect, btn->position);
                painter->setPen(btn->borderColor);
                painter->fillPath(framePath, btn->backgroundColor);
                if (!(btn->state & State_Enabled)) {
                    painter->setOpacity(0.3);
                }
                painter->drawPath(UWidgetUtils::roundedPath(btn->radius, btn->rect.adjusted(1, 1, -1, -1), btn->position));
                painter->setOpacity(1.0);
                drawButtonContents(btn, painter, widget, btn->alignment, btn->foregroundColor);
            }
            break;
        case CE_UTagWidget:
            if (const UTagWidgetStyleOption* opt = qstyleoption_cast<const UTagWidgetStyleOption*>(option))
            {
                painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
                QPainterPath framePath;
                framePath.addRoundedRect(opt->rect, 4, 4);
                painter->setPen(opt->borderColor);
                painter->fillPath(framePath, opt->backgroundColor);
                painter->drawPath(framePath);

                auto textRect = opt->rect;
                if (opt->isEdit)
                {
                    textRect.setWidth(opt->rect.width() - opt->rect.height());
                }
                textRect.setX(opt->margins);
                if (!opt->text.isEmpty())
                {
                    QString text = opt->fontMetrics.elidedText(opt->text, Qt::ElideMiddle, textRect.width());
                    painter->setPen(opt->foregroundColor);
                    drawItemText(painter, textRect, Qt::TextSingleLine | static_cast<int>(Qt::AlignCenter),
                                 opt->palette, opt->state & State_Enabled, text, QPalette::NoRole);
                }
            }
            break;
        default:
            break;
    }
}

void UProxyStyle::drawPrimitive(QStyle::PrimitiveElement element,
                                const QStyleOption* option,
                                QPainter* painter,
                                const QWidget* widget) const
{
    switch (element)
    {
        case QStyle::PE_FrameMenu: //整个菜单widget的边框色
        {
            qDrawShadeRect(painter, option->rect, option->palette, option->state & State_Sunken, 1);
            break;
        }
        case QStyle::PE_PanelMenu: //整个菜单widget的背景色
        {
            painter->setRenderHint(QPainter::Antialiasing);
            QPainterPath path;
            path.addRoundedRect(option->rect, FRAME_BORDER_RADIUS, FRAME_BORDER_RADIUS);
            painter->setClipPath(path);
            QStyle::State widgetState;
            if (widget && widget->isActiveWindow())
                widgetState |= QStyle::State_Active;
            if (widget && widget->isEnabled())
                widgetState |= QStyle::State_Enabled;
            painter->fillPath(path, option->palette.brush(QPalette::Base));
            break;
        }
        case PE_PanelLineEdit:
            break;
        case PE_IndicatorItemViewItemCheck:
        {
            QRect rect = option->rect;
            bool selected = false;
            if (option->state & QStyle::State_Enabled)
            {
                if (option->state & QStyle::State_Selected)
                {
                    selected = true;
                }
            }
            painter->save();
            auto group = colorGroup(option, widget);
            painter->setBrush(selected ? option->palette.color(group, QPalette::HighlightedText) :
                              option->palette.color(group, QPalette::Highlight));
            QColor color = selected ? option->palette.color(group, QPalette::Highlight) :
                           option->palette.color(group, QPalette::HighlightedText);
            painter->setPen(Qt::NoPen);
            painter->drawEllipse(rect);
            painter->setPen(QPen(color, 2));
            painter->drawLine(rect.center().x() - 4, rect.center().y(), rect.center().x(), rect.center().y() + 5);
            painter->drawLine(rect.center().x(), rect.center().y() + 5, rect.center().x() + 6, rect.center().y() - 3);
            painter->restore();
            break;
        }
        case PE_PanelItemViewRow:
        {
            if (const QStyleOptionViewItem* vopt = qstyleoption_cast<const QStyleOptionViewItem*>(option))
            {
                QPalette::ColorGroup cg = colorGroup(vopt, widget);
                if ((vopt->state & QStyle::State_Selected) &&
                    proxy()->styleHint(QStyle::SH_ItemView_ShowDecorationSelected, option, widget))
                    painter->fillPath(backgroundPath(*vopt, pixelMetric(UPixelMetric::PM_FrameRadius, vopt, widget)),
                                      vopt->palette.brush(cg, QPalette::Highlight));
                else if (vopt->features & QStyleOptionViewItem::Alternate)
                    painter->fillPath(backgroundPath(*vopt, pixelMetric(UPixelMetric::PM_FrameRadius, vopt, widget)),
                                      vopt->palette.brush(cg, QPalette::AlternateBase));
            }
            break;
        }
        default:
            QProxyStyle::drawPrimitive(element, option, painter, widget);
            break;
    }
}

void UProxyStyle::drawPrimitive(UPrimitiveElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
{
    switch (element)
    {
        case PE_IndicatorCheckBox:
        {
            if (!(option->state & State_Enabled)) {
                painter->setOpacity(0.3);
            }
            QRect rect = option->rect;
            painter->setRenderHint(QPainter::Antialiasing);
            QColor color = option->palette.color(QPalette::WindowText);
            if (option->state & State_Sunken)
            {
                color = option->palette.color(QPalette::Highlight);
            }
            else if (option->state & State_MouseOver)
            {
                painter->setPen(Qt::NoPen);
                painter->setBrush(option->palette.brush(QPalette::Button));
                painter->drawRoundedRect(rect, 2, 2);
            }

            painter->setPen(QPen(color, 1));
            painter->setBrush(Qt::NoBrush);
            painter->drawRoundedRect(rect, 2, 2);

            if (option->state & State_On)
            {
                painter->setPen(QPen(option->palette.brush(QPalette::WindowText), 2));
                painter->drawLine(rect.x() + 3, rect.center().y(), rect.center().x(), rect.y() + rect.height() - 4);
                painter->drawLine(rect.center().x(), rect.y() + rect.height() - 4, rect.x() + rect.width() - 3, rect.y() + rect.height() / 4);
            }
            else if (option->state & State_NoChange)
            {
                painter->setPen(QPen(option->palette.brush(QPalette::WindowText), 2));
                painter->drawLine(rect.x() + 3, rect.center().y(), rect.x() + rect.width() - 3, rect.center().y());
            }
            painter->setOpacity(1.0);
            break;
        }
        case PE_IndicatorRadioButton:
        {
            if (!(option->state & State_Enabled)) {
                painter->setOpacity(0.3);
            }
            QRectF rect = QRectF(0.5, 0.5, option->rect.width(), option->rect.width());
            painter->setRenderHints(QPainter::Antialiasing);
            QColor color = option->palette.color(QPalette::WindowText);
            if (option->state & State_Sunken)
            {
                color = option->palette.color(QPalette::Highlight).darker(120);
            }
            else if (option->state & State_MouseOver)
            {
                color = option->palette.color(QPalette::Highlight);
            }
            if (option->state & State_On)
            {
                painter->setBrush(color);
                painter->setPen(Qt::NoPen);
                painter->drawEllipse(rect.adjusted(2, 2, -2, -2));
            }
            else if (option->state & State_NoChange)
            {
                painter->setPen(QPen(color, 2));
                painter->drawLine(QPointF(rect.x() + 3, rect.center().y()), QPointF(rect.x() + rect.width() - 3, rect.center().y()));
            }
            painter->setPen(QPen(color));
            painter->setBrush(Qt::NoBrush);
            painter->drawEllipse(rect);
            painter->setOpacity(1.0);
            break;
        }
        case PE_SettingsItem:
        {
            if (const USettingsItemStyleOption* opt = static_cast<const USettingsItemStyleOption*>(option))
            {
                QPainterPath path = UWidgetUtils::roundedPath(pixelMetric(UPixelMetric::PM_FrameRadius, opt, widget), opt->rect,
                                    radiuPosition(opt->viewItemPosition));
                auto color = opt->backgroundColor;
                if (!(opt->state & State_Enabled)) {
                    color.setAlphaF(0.3);
                }
                painter->fillPath(path, color);
                uint alignment = visualAlignment(opt->direction, Qt::AlignLeft | Qt::AlignVCenter);
                QPixmap pix;
                QRect textRect = opt->rect.adjusted(6, 0, 0, 0);
                if (!opt->icon.isNull())
                {
                    pix = getIconPixmap(opt->state, opt->icon, opt->iconSize);
                    drawItemPixmap(painter, textRect, alignment, pix);
                    if (opt->direction == Qt::RightToLeft)
                        textRect.setRight(textRect.right() - opt->iconSize.width() - 4);
                    else
                        textRect.setLeft(textRect.left() + opt->iconSize.width() + 4);
                }
                if (!opt->text.isEmpty())
                {
                    drawItemText(painter, textRect, alignment | Qt::TextShowMnemonic,
                                 opt->palette, opt->state & State_Enabled, opt->text, QPalette::WindowText);
                }
            }
            break;
        }
        case PE_UScrollBar:
        {
            if (const QStyleOptionSlider* scrollbar = qstyleoption_cast<const QStyleOptionSlider*>(option))
            {
                qreal opacity = painter->opacity();
                painter->setRenderHint(QPainter::Antialiasing);
                painter->setOpacity(1.0);
                painter->fillRect(scrollbar->rect, option->palette.brush(QPalette::Window));
                painter->setBrush(Qt::transparent);
                painter->setPen(Qt::NoPen);

                QPainterPath path;
                path.addRoundedRect(scrollbar->rect, 4, 4);
                painter->setClipPath(path);
                painter->drawRect(scrollbar->rect);

                if (scrollbar->subControls & SC_ScrollBarSlider)
                {
                    QRect sliderRect = proxy()->subControlRect(CC_ScrollBar, scrollbar, SC_ScrollBarSlider, widget);
                    if (sliderRect.isValid())
                    {
                        QColor sliderColor = option->palette.color(QPalette::Button);
                        if ((scrollbar->activeSubControls & SC_ScrollBarSlider))
                        {
                            if (scrollbar->state & State_MouseOver)
                            {
                                sliderColor = sliderColor.darker(110);
                            }
                            if (scrollbar->state & State_Sunken)
                            {
                                sliderColor = sliderColor.darker(120);
                            }
                        }
                        painter->setOpacity(opacity);
                        painter->setBrush(sliderColor);
                        painter->drawRoundedRect(sliderRect, 4, 4);
                    }
                }
            }
            break;
        }
        default:
            break;
    }
}

void UProxyStyle::drawComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget) const
{
    switch (control)
    {
        case CC_ScrollBar:
            drawPrimitive(UPrimitiveElement::PE_UScrollBar, option, painter, widget);
            break;
        case CC_Slider:
            if (const QStyleOptionSlider* styleOptionSlider = qstyleoption_cast<const QStyleOptionSlider*>(option))
            {
                if (!(styleOptionSlider->state & State_Enabled)) {
                    painter->setOpacity(0.3);
                }
                QRect grooveRect = subControlRect(CC_Slider, styleOptionSlider, SC_SliderGroove, widget);
                grooveRect = QRect(grooveRect.x(), grooveRect.y() + grooveRect.height() / 2 - 5, grooveRect.width(), 10);
                painter->setPen(Qt::NoPen);
                painter->setBrush(styleOptionSlider->palette.brush(QPalette::Button));

                painter->setRenderHint(QPainter::Antialiasing, true);
                painter->drawRoundedRect(grooveRect, 4, 4);

                QRect handleRect = subControlRect(CC_Slider, styleOptionSlider, SC_SliderHandle, widget);
                int width = qMin(handleRect.width(), handleRect.height());
                handleRect = QRect(handleRect.x(), handleRect.y() + (handleRect.height() - width) / 2, width, width);
                painter->setPen(Qt::gray);
                painter->setBrush(Qt::white);
                painter->drawEllipse(handleRect);
                painter->setOpacity(1.0);
            }
            break;
        default:
            QProxyStyle::drawComplexControl(control, option, painter, widget);
            break;
    }
}

void UProxyStyle::drawComplexControl(UComplexControl control, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget) const
{
    switch (control)
    {
        case CC_UScrollBar:
            drawPrimitive(UPrimitiveElement::PE_UScrollBar, option, painter, widget);
            break;
        default:
            break;
        }
}

void UProxyStyle::drawItemText(QPainter *painter, const QRect &rect, int alignment, const QPalette &pal, bool enabled, const QString &text, QPalette::ColorRole textRole) const
{
    if (text.isEmpty())
        return;
    QPen savedPen;
    if (textRole != QPalette::NoRole) {
        savedPen = painter->pen();
        painter->setPen(QPen(pal.brush(textRole), savedPen.widthF()));
    }
    if (!enabled) {
        painter->setOpacity(0.3);
    }
    painter->drawText(rect, alignment, text);
    painter->setOpacity(1.0);
    if (textRole != QPalette::NoRole)
        painter->setPen(savedPen);
}

QPalette::ColorGroup UProxyStyle::colorGroup(const QStyleOption* option, const QWidget* widget)
{
    bool isEnabled = widget ? widget->isEnabled() : (option->state & QStyle::State_Enabled);
    QPalette::ColorGroup group;
    if (!isEnabled)
        group = QPalette::Disabled;
    else
        group = widget ? (!widget->isActiveWindow() ? QPalette::Inactive : QPalette::Active) : QPalette::Inactive;

    return group;
}

QPainterPath UProxyStyle::backgroundPath(const QStyleOptionViewItem &option, int radius)
{
    QPainterPath path;
    QRect rect = option.rect;
    switch (option.viewItemPosition)
    {
        case QStyleOptionViewItem::ViewItemPosition::Beginning:
        {
            path.addRoundedRect(rect, radius, radius);
            rect.setX(rect.width() / 2);
            QPainterPath addPath;
            addPath.addRect(rect);
            path = path.united(addPath);
            break;
        }
        case QStyleOptionViewItem::ViewItemPosition::Middle:
        {
            path.addRect(rect);
            break;
        }
        case QStyleOptionViewItem::ViewItemPosition::End:
        {
            path.addRoundedRect(rect, radius, radius);
            rect.setWidth(rect.width() / 2);
            QPainterPath addPath;
            addPath.addRect(rect);
            path = path.united(addPath);
            break;
        }
        case QStyleOptionViewItem::ViewItemPosition::OnlyOne:
        {
            path.addRoundedRect(rect, radius, radius);
            break;
        }
        default:
            break;
    }

    return path;
}

void UProxyStyle::drawMenuItem(const QStyleOptionMenuItem* menuItem,
                               QPainter* painter) const
{
    drawMenuItemIcon(menuItem, painter);
    painter->setPen(menuItem->palette.color(colorGroup(menuItem->state), QPalette::Text));
    QRect textRect = menuItem->rect;
    textRect = textRect.adjusted(MARGINS, 0, -MARGINS, 0);
    QFont font = menuItem->font;
    painter->setFont(font);
    int text_flags = Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
    QString title;
    QString shortcutText;
    if (menuItem->text.contains(QLatin1Char('\t')))
    {
        QStringList list = menuItem->text.split(QLatin1Char('\t'));
        if (list.size() > 1)
            shortcutText = list.at(1);
        title = list.at(0);
    }
    else
    {
        title = menuItem->text;
    }

    if (!shortcutText.isEmpty())  //画快捷键文字
    {
        int x, y, w, h;
        menuItem->rect.getRect(&x, &y, &w, &h);
        int dim = (h - 2 * 2) / 2;
        int xpos = x + w - 2 - 1 - dim;
        QRect vSubMenuRect = visualRect(menuItem->direction, menuItem->rect, QRect(xpos, y + h / 2 - dim / 2, dim, dim));
        int fw = menuItem->fontMetrics.horizontalAdvance(shortcutText);
        textRect.moveLeft(menuItem->rect.right() - fw - vSubMenuRect.width());
        textRect = visualRect(menuItem->direction, menuItem->rect, textRect);
        drawItemText(painter, textRect, text_flags,
                     menuItem->palette, menuItem->state & State_Enabled, shortcutText, QPalette::Text);
    }

    textRect.moveLeft(LEFT_MARGIN);
    textRect = visualRect(menuItem->direction, menuItem->rect, textRect);
    drawItemText(painter, textRect, text_flags,
                 menuItem->palette, menuItem->state & State_Enabled, title, QPalette::Text);
}

void UProxyStyle::drawSeparator(const QStyleOptionMenuItem* menuItem,
                                QPainter* painter) const
{
    QRect rect = menuItem->rect.adjusted(MARGINS, 0, -MARGINS, 0);
    painter->setPen(QPen(Qt::black));
    painter->drawLine(rect.left(), rect.center().y(), rect.right(), rect.center().y());
}

void UProxyStyle::drawMenuItemIcon(const QStyleOptionMenuItem* menuItem,
                                   QPainter* painter) const
{
    QPixmap pixmap = getIconPixmap(menuItem->state,
                                   menuItem->icon,
                                   QSize(ICON_PIXEL_SIZE,
                                         ICON_PIXEL_SIZE));
    if (pixmap.isNull())
    {
        return;
    }
    int x = ICON_LEFT_MARGIN + MARGINS;
    int y = menuItem->rect.y() + (menuItem->rect.height() - pixmap.height()) / 2;
    painter->drawPixmap(x, y, pixmap.width(), pixmap.height(), pixmap);
}

void UProxyStyle::drawSubMenuItem(const QStyleOptionMenuItem* menuItem,
                                  QPainter* painter) const
{
    drawMenuItemIcon(menuItem, painter);
    QRect textRect = menuItem->rect;
    textRect = textRect.adjusted(MARGINS, 0, -MARGINS, 0);
    textRect.moveLeft(LEFT_MARGIN);
    painter->setPen(menuItem->palette.text().color());
    drawItemText(painter, textRect, Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextSingleLine | Qt::TextDontClip,
                 menuItem->palette, menuItem->state & State_Enabled, menuItem->text, QPalette::Text);
    int x, y, w, h;
    menuItem->rect.getRect(&x, &y, &w, &h);
    int dim = (h - 2 * 2) / 2;
    int xpos = x + w - 2 - 1 - dim;
    QRect vSubMenuRect = visualRect(menuItem->direction, menuItem->rect, QRect(xpos, y + h / 2 - dim / 2, dim, dim));
    painter->drawPixmap(vSubMenuRect, getSubMenuPixmap(menuItem->state));
}

QPixmap UProxyStyle::getSubMenuPixmap(const QStyle::State state) const
{
    return getIconPixmap(state, QIcon::fromTheme("sub_menu"), QSize(10, 10));
}

QPixmap UProxyStyle::getIconPixmap(const State &state, const QIcon &icon, const QSize &size)
{
    if (!icon.isNull())
    {
        QIcon::Mode iconMode = QIcon::Normal;
        QIcon::State iconState = QIcon::Off;

        if (state & QStyle::State_Enabled)
        {
            if (state & QStyle::State_Selected || state & State_Sunken)
            {
                iconMode = QIcon::Selected;
            }
            else if (state & QStyle::State_Active)
            {
                iconMode = QIcon::Active;
            }
        }
        else
        {
            iconMode = QIcon::Disabled;
        }

        if (state & QStyle::State_On)
        {
            iconState = QIcon::On;
        }

        return icon.pixmap(size, iconMode, iconState);
    }
    else
    {
        return QPixmap();
    }
}

void UProxyStyle::qDrawPlainRoundedRect(QPainter* p, const QRect &r, const QColor &c, int lineWidth, const QBrush* fill, int radius)
{
    int x = r.x();
    int y = r.y();
    int w = r.width();
    int h = r.height();
    if (w == 0 || h == 0)
        return;
    if (Q_UNLIKELY(w < 0 || h < 0 || lineWidth < 0))
    {
        qWarning("qDrawPlainRoundedRect: Invalid parameters");
    }

    const qreal devicePixelRatio = p->device()->devicePixelRatioF();
    p->save();
    p->setRenderHints(QPainter::Antialiasing);
    if (!qFuzzyCompare(devicePixelRatio, qreal(1)))
    {
        const qreal inverseScale = qreal(1) / devicePixelRatio;
        p->scale(inverseScale, inverseScale);
        x = qRound(devicePixelRatio * x);
        y = qRound(devicePixelRatio * y);
        w = qRound(devicePixelRatio * w);
        h = qRound(devicePixelRatio * h);
        lineWidth = qRound(devicePixelRatio * lineWidth);
    }

    QPen oldPen = p->pen();
    QBrush oldBrush = p->brush();
    p->setPen(c);
    p->setBrush(Qt::NoBrush);
    for (int i = 0; i < lineWidth; i++)
        p->drawRoundedRect(x + i, y + i, w - i * 2 - 1, h - i * 2 - 1, radius, radius);
    if (fill)
    {
        p->setPen(Qt::NoPen);
        p->setBrush(*fill);
        p->drawRoundedRect(x + lineWidth, y + lineWidth, w - lineWidth * 2, h - lineWidth * 2, radius, radius);
    }
    p->setPen(oldPen);
    p->setBrush(oldBrush);
    p->restore();
}

QPalette::ColorGroup UProxyStyle::colorGroup(const QStyle::State state) const
{
    QPalette::ColorGroup group;

    if (!(state & QStyle::State_Enabled))
        group = QPalette::Disabled;
    else
        group = QPalette::Active;

    return group;
}

void UProxyStyle::drawButtonContents(const QStyleOptionButton *btn, QPainter *painter, const QWidget *widget,
                                     uint btnAlignment, const QColor &foregroundColor) const
{
    auto textRect = subElementRect(SE_PushButtonContents, btn, widget);
    uint alignment = visualAlignment(btn->direction, Qt::AlignLeft | Qt::AlignVCenter);
    QPixmap pix;
    if (!btn->icon.isNull())
    {
        textRect.setX(textRect.x() + 8);
        pix = getIconPixmap(btn->state, btn->icon, btn->iconSize);
        drawItemPixmap(painter, textRect, alignment, pix);
        if (btn->direction == Qt::RightToLeft)
            textRect.setRight(textRect.right() - btn->iconSize.width() - 4);
        else
            textRect.setLeft(textRect.left() + btn->iconSize.width() + 4);
    }
    if (!btn->text.isEmpty())
    {
        QString text = btn->fontMetrics.elidedText(btn->text, Qt::ElideMiddle, textRect.width());
        painter->setPen(foregroundColor);
        drawItemText(painter, textRect, Qt::TextSingleLine | btnAlignment,
                     btn->palette, btn->state & State_Enabled, text, QPalette::NoRole);
    }
}
